package com.qqt.csr.route.service;

import com.google.common.collect.Lists;
import com.qqt.csr.common.enums.YesOrNotEnum;
import com.qqt.csr.common.exception.StatusCode;
import com.qqt.csr.common.utils.ServiceAssert;
import com.qqt.csr.im.entity.msg.Message;
import com.qqt.csr.im.entity.msg.TextContent;
import com.qqt.csr.im.enums.MsgTypeEnum;
import com.qqt.csr.route.dto.resp.RouteResultDTO;
import com.qqt.csr.route.entity.RouteBizRule;
import com.qqt.csr.route.entity.RouteDistributionRule;
import com.qqt.csr.route.entity.RouteTask;
import com.qqt.csr.route.enums.RouteTaskEventEnum;
import com.qqt.csr.route.enums.RouteTaskStatusEnum;
import com.qqt.csr.route.service.strategy.cs.CsLastLeastDistribution;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.Random;

/**
 * 路由分发
 *
 * @author
 */
@Slf4j
@Service
public class DistributingRouteService {
    @Autowired
    private RouteDistributionRuleService routeDistributionRuleService;
    @Autowired
    private RouteTaskService routeTaskService;
    @Autowired
    private RouteSkillSetService routeSkillSetService;
    @Autowired
    private RouteCsService routeCsService;
    @Autowired
    private VisitorQueueService visitorQueueService;
    @Autowired
    private ServiceTimeService serviceTimeService;
    @Autowired
    private RouteMqProducerService routeMqProducerService;
    @Autowired
    private CsReceptionLimitService csReceptionLimitService;
    @Autowired
    private ConversationStatService conversationStatService;
    @Autowired
    private CsLastLeastDistribution csLastLeastDistribution;

    /**
     * 推送多个业务规则提示给访客进行选择
     *
     * @param routeTask
     */
    public void pushMultiBizRuleToVisitor(RouteTask routeTask) {
        RouteDistributionRule routeRule = routeTask.getRouteRule();
        if (routeRule.getRouteBizRuleList().size() > 1) {
            // 返回业务集合提示给到访客选择
            routeTaskService.save(routeTask);
            routeMqProducerService.sendRouteResult(RouteResultDTO.of(routeTask, routeRule.getMultiBizRuleTip(), null));
            return;
        }

        // 如果是单业务规则配置，默认取第一个业务规则，无需访客选择，并继续走分发逻辑
        RouteBizRule routeBizRule = routeRule.getRouteBizRuleList().get(0);
        if (isMatchBizRuleServiceTime(routeTask, routeBizRule)) {
            distribute(routeTask, routeBizRule);
        }
    }

    /**
     * 根据访客输入的消息内容，进行业务规则选择或者退出排队
     *
     * @param message
     */
    public void handleVisitorMsg(Message message) {
        if (message == null || !MsgTypeEnum.TextElem.equals(message.getType())
                || message.getContent() == null
                || !(message.getContent() instanceof TextContent msgContent)
                || StringUtils.isBlank(msgContent.getText())) {
            return;
        }

        RouteTask routeTask = routeTaskService.queryByConversationId(message.getConversationId(), Lists.newArrayList(RouteTaskStatusEnum.UN_ROUTE, RouteTaskStatusEnum.QUEUE));
        if (routeTask == null || routeTask.getRouteRule() == null) {
            return;
        }
        RouteDistributionRule routeRule = routeTask.getRouteRule();

        if (RouteTaskStatusEnum.QUEUE.equals(routeTask.getStatus())) {
            if (routeRule.isQuitQueue(msgContent.getText())) {
                // 排队中的话，访客主动触发访客退出词
                if (routeTask.getSkillSet() != null) {
                    visitorQueueService.remove(routeTask.getSkillSet().getSkillSetId(), routeTask.getId());
                }
                routeTask.addEvent(RouteTaskEventEnum.VISITOR_OUT_QUEUE);
                routeTaskService.save(routeTask);
                routeMqProducerService.sendRouteResult(RouteResultDTO.of(routeTask, routeRule.getQuitQueueWordTip(), null));
            }
            return;
        }

        if (RouteTaskStatusEnum.UN_ROUTE.equals(routeTask.getStatus())) {
            // 访客选择业务规则
            RouteBizRule routeBizRule = routeRule.chooseBizRule(msgContent.getText());
            if (routeBizRule == null) {
                // 记录业务选择错误次数
                routeTask.increaseBizSelectErrorCount();
                if (routeTask.getBizSelectErrorCount() >= routeRule.getBizSelectErrorCount()) {
                    // 达到业务选择错误次数上限
                    if (routeRule.getBizSelectErrorAction().equals(0)) {
                        // 直接退出
                        routeTask.addEvent(RouteTaskEventEnum.SELECTED_BIZ_ERROR_LIMIT);
                        routeTaskService.save(routeTask);
                        routeMqProducerService.sendRouteResult(RouteResultDTO.of(routeTask, routeRule.getBizSelectErrorQuitTip(), null));
                        return;
                    } else {
                        // 随机分配业务规则
                        routeBizRule = routeRule.getRouteBizRuleList().get(new Random().nextInt(routeRule.getRouteBizRuleList().size()));
                    }
                } else {
                    // 未达到业务选择错误次数上限，继续让访客选择
                    routeTaskService.save(routeTask);
                    routeMqProducerService.sendRouteResult(RouteResultDTO.of(routeTask, routeRule.getBizSelectErrorTip(), null));
                    return;
                }
            }

            // 命中业务规则或者随机分配了业务规则
            if (isMatchBizRuleServiceTime(routeTask, routeBizRule)) {
                distribute(routeTask, routeBizRule);
            }
        }
    }

    /**
     * 分发路由
     *
     * @param routeTask
     */
    public void distribute(RouteTask routeTask, RouteBizRule routeBizRule) {
        routeTask.setRouteBizRule(routeBizRule);
        routeTask.addEvent(RouteTaskEventEnum.MATCHED_BIZ);
        // 配置计划选择技能组集合
        routeTask.setPlanSkillSetIdList(routeBizRule.getSkillSetIdList());

        try {
            if (routeBizRule.getAcquaintanceFirst().equals(YesOrNotEnum.YES.getValue())) {
                // 熟客优先
                RouteResultDTO routeResultDTO = RouteResultDTO.of(routeTask, null, null);
                csLastLeastDistribution.distribution(routeTask, routeResultDTO);
                if (RouteTaskStatusEnum.ROUTED.equals(routeTask.getStatus()) && routeTask.getCsId() != null) {
                    // 记录业务规则分配技能组的会话数量
                    conversationStatService.increaseConversationCount(routeTask.getTenantId(), routeTask.getSkillSet().getSkillSetId());
                    routeTaskService.save(routeTask);
                    sendRouteResultToMq(routeTask, routeResultDTO);
                    return;
                }
            }

            // 不满足熟客优先，则按分发规则分发技能组
            distribute(routeTask, routeBizRule.getDistributeType());
        } catch (Exception e) {
            log.error("路由分发异常,routeTaskId:{}", routeTask.getId(), e);
            if (RouteTaskStatusEnum.ROUTED.equals(routeTask.getStatus()) && routeTask.getCsId() != null) {
                csReceptionLimitService.release(routeTask.getCsId(), 1);
            }
        }
    }

    /**
     * 指定技能组分发策略，路由分发
     * @param routeTask
     * @param distributeType
     */
    public void distribute(RouteTask routeTask, Integer distributeType) {
        RouteResultDTO routeResultDTO = RouteResultDTO.of(routeTask, null, null);
        try {
            routeSkillSetService.route(routeTask, routeResultDTO, distributeType);
            if (RouteTaskStatusEnum.FAIL.equals(routeTask.getStatus())) {
                routeTaskService.save(routeTask);
                sendRouteResultToMq(routeTask, routeResultDTO);
                return;
            }

            int queueSize = visitorQueueService.size(routeTask.getSkillSet().getSkillSetId());
            if (queueSize > 0) {
                // 队列中有访客在排队，则直接加入到队列
                visitorQueueService.add(routeTask, routeResultDTO);
                routeTaskService.save(routeTask);
                sendRouteResultToMq(routeTask, routeResultDTO);
                return;
            }

            // 分配客服
            routeCsService.route(routeTask, routeResultDTO);
            if (RouteTaskStatusEnum.ROUTED.equals(routeTask.getStatus())) {
                routeTaskService.save(routeTask);
                sendRouteResultToMq(routeTask, routeResultDTO);
                return;
            }

            // 访客排队
            visitorQueueService.add(routeTask, routeResultDTO);
            routeTaskService.save(routeTask);
            sendRouteResultToMq(routeTask, routeResultDTO);
        } catch (Exception e) {
            log.error("路由分发异常,routeTaskId:{}", routeTask.getId(), e);
            if (RouteTaskStatusEnum.ROUTED.equals(routeTask.getStatus()) && routeTask.getCsId() != null) {
                csReceptionLimitService.release(routeTask.getCsId(), 1);
            }
        }
    }

    /**
     * 是否在业务规则的服务时间内
     *
     * @param routeTask
     * @return
     */
    private boolean isMatchBizRuleServiceTime(RouteTask routeTask, RouteBizRule routeBizRule) {
        ServiceAssert.notNull(routeBizRule, StatusCode.Common.NOT_EXIST.getCode(), "无效分配配置！", String.format("未匹配具体业务规则, taskId:%s", routeTask.getId()));
        boolean isWorkTime = serviceTimeService.match(routeTask.getTenantId(), routeBizRule.getBizTimeId(), new Date());
        if (!isWorkTime) {
            // 不在服务时间内，直接返回提示给到访客
            routeTask.addEvent(RouteTaskEventEnum.NOT_MATCHED_BIZ_TIME);
            routeTaskService.save(routeTask);
            routeMqProducerService.sendRouteResult(RouteResultDTO.of(routeTask, routeBizRule.getRestTimeInTip(), null));
        }
        return isWorkTime;
    }

    private void sendRouteResultToMq(RouteTask routeTask, RouteResultDTO routeResultDTO) {
        routeResultDTO.getRouteTaskDTO().setStatus(routeTask.getStatus());
        routeMqProducerService.sendRouteResult(routeResultDTO);
    }


}
